﻿using System;
using System.Linq;
using System.Drawing;
using System.Collections.Generic;
using System.Windows.Forms;
using Syncfusion.Drawing;
using Syncfusion.Grouping;
using Syncfusion.Windows.Forms;
using Syncfusion.Windows.Forms.Grid;
using Syncfusion.GridHelperClasses;
using Syncfusion.Windows.Forms.Grid.Grouping;
using PMngr.Data;

namespace PMngr.Main
{
    public partial class MstUnits : BaseControl
    {
        private IRepositoryFactory repositoryFactory;
     
        public MstUnits()
        {
            InitializeComponent();
            InitializeGridGrouping();            
        }

        public MstUnits(IRepositoryFactory repositoryFactory)
            : this()
        {
            this.repositoryFactory = repositoryFactory;
        }

        public override void InitializeControls()
        {
            InitializeDropDownList();

            ComUnitTypeSelectionChangeCommitted(this, EventArgs.Empty);
        }

        private void ComUnitTypeSelectionChangeCommitted(object sender, EventArgs e)
        {
            var selected = comUnitType.SelectedValue;
            if (selected == null) return;

            var unitType = (int)selected;
            ResetGridByIndex(unitType, 0);
        }

        private void ResetGrid(int unitType, int? unitId)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var units = repository.Find<Unit>(item => item.UnitType.Code == unitType);
                var datasource = from u in units
                                 orderby u.Id
                                 select new UnitModel
                                            {
                                                Id = u.Id,
                                                Name = u.Name,
                                                Subsidiary = u.ChildUnits.Where(i => i.IsValid).Count(),
                                                Contact = u.Contact,
                                                ContactTel = u.ContactTel,
                                                UnitTypeCode = u.UnitType.Code,
                                                Address = u.Address,
                                                IsValid = u.IsValid
                                            };

                glUnits.DataSource = datasource.ToList();
                glUnits.Appearance.AnyRecordFieldCell.CellTipText = glUnits.Appearance.AnyRecordFieldCell.Text;
                // set the selected item in current row status
                if (glUnits.Table.Records.Count > 0)
                {
                    foreach (Record record in glUnits.Table.Records)
                    {
                        if (record.IsRecord())
                        {
                            var value = record.GetValue(UnitModel.GetPropertyName(u => u.Id));
                            if (value != null)
                            {
                                if (unitId == (int) value)
                                {
                                    glUnits.Table.SelectedRecords.Add(record);
                                    glUnits.Table.CurrentRecord = record;
                                }
                            }
                        }
                    }
                }
                else
                {
                    ResetDetails();
                }
            }
        }

        private void ResetGridByIndex(int unitType, int index)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var units = repository.Find<Unit>(item => item.UnitType.Code == unitType);
                var datasource = from u in units
                                 orderby u.Id
                                 select new UnitModel
                                            {
                                                Id = u.Id,
                                                Name = u.Name,
                                                Subsidiary = u.ChildUnits.Count,
                                                Contact = u.Contact,
                                                ContactTel = u.ContactTel,
                                                UnitTypeCode = u.UnitType.Code,
                                                Address = u.Address,
                                                IsValid = u.IsValid
                                            };

                glUnits.DataSource = datasource.ToList();
                glUnits.Appearance.AnyRecordFieldCell.CellTipText = glUnits.Appearance.AnyRecordFieldCell.Text;
                //
                if (glUnits.Table.Records.Count > 0)
                {
                    glUnits.Table.SelectedRecords.Add(glUnits.Table.Records[index]);
                    glUnits.Table.CurrentRecord = glUnits.Table.Records[index];
                }
                else
                {
                    ResetDetails();
                }
            }
        }

        #region GridGroupingControl Settings
        private void InitializeGridGrouping()
        {
            var gcd = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.Id),
                                              UnitModel.GetPropertyName(u => u.Id),
                                              UnitModel.Dict[UnitModel.GetPropertyName(u => u.Id)]);
            glUnits.TableDescriptor.Columns.Add(gcd);
            var gcd1 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.Name),
                                                UnitModel.GetPropertyName(u => u.Name),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.Name)]) { Width = 250 };
            glUnits.TableDescriptor.Columns.Add(gcd1);
            var gcd2 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.Subsidiary),
                                                UnitModel.GetPropertyName(u => u.Subsidiary),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.Subsidiary)], true, 80);
            glUnits.TableDescriptor.Columns.Add(gcd2);
            var gcd3 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.Contact),
                                                UnitModel.GetPropertyName(u => u.Contact),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.Contact)], true, 80);
            glUnits.TableDescriptor.Columns.Add(gcd3);
            var gcd4 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.ContactTel),
                                                UnitModel.GetPropertyName(u => u.ContactTel),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.ContactTel)], true, 100);
            glUnits.TableDescriptor.Columns.Add(gcd4);
            var gcd5 = new GridColumnDescriptor(UnitModel.GetPropertyName(u => u.Address),
                                                UnitModel.GetPropertyName(u => u.Address),
                                                UnitModel.Dict[UnitModel.GetPropertyName(u => u.Address)], true, 200);
            glUnits.TableDescriptor.Columns.Add(gcd5);
            // hide the trivial items
            glUnits.TableDescriptor.VisibleColumns.Remove(UnitModel.GetPropertyName(u => u.Id));

            glUnits.InitializeGridGroupingWithFilterAndFormat("[IsValid] LIKE 'false'");

            glUnits.DataSource = null;
            // event
            glUnits.TableControlMouseDown += GlUnitsTableControlMouseDown;
        }
        #endregion

        private void InitializeDropDownList()
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var options = repository.All<ItemBase>();
                var datasource = from o in options
                                 where o.Type == "UnitType" && o.IsValid
                                 orderby o.Order ascending
                                 select new {o.Code, o.Name};
                var result = datasource.ToList();
                comUnitType.DataSource = result;
                comUnitType.DisplayMember = ItemModel.GetPropertyName(u => u.Name);
                comUnitType.ValueMember = ItemModel.GetPropertyName(u => u.Code);
                // 增强型需求
                comUnitType.ImageList = imageList;
                var count = comUnitType.ImageIndexes.Count;
                for (var i = 0; i < count; i++)
                    comUnitType.ImageIndexes[i] = 0;
            }
        }    

        void GlUnitsTableControlMouseDown(object sender, GridTableControlMouseEventArgs e)
        {
            if (e.Inner.Button == MouseButtons.Right)
            {
                int row, col;
                var pt = new Point(e.Inner.X, e.Inner.Y);

                if (e.TableControl.PointToRowCol(pt, out row, out col))
                    e.TableControl.CurrentCell.AdjustRowColIfCoveredCell(ref row, ref col);

                var style = e.TableControl.GetTableViewStyleInfo(row, col);
                if (style.TableCellIdentity.DisplayElement.Kind != DisplayElementKind.ColumnHeader)
                    contextMenu.Show(e.TableControl, pt);
            }
        }

        private void BuildUpDetails(int? unitId)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                if (unitId.HasValue)
                {
                    var unit = repository.Find<Unit>(unitId);

                    txtUnit.Text = unit.Name;
                    txtAddress.Text = unit.Address;
                    txtContact.Text = unit.Contact;
                    txtTel.Text = unit.ContactTel;
                    txtDesc.Text = unit.Description;
                    chkValid.Checked = unit.IsValid;
                }
            }
        }

        private void ResetDetails()
        {
            txtUnit.Text = String.Empty;
            txtAddress.Text = String.Empty;
            txtContact.Text = String.Empty;
            txtTel.Text = String.Empty;
            txtDesc.Text = String.Empty;
            chkValid.Checked = true;
        }

        private void AddNewUnitToolStripMenuItemClick(object sender, EventArgs e)
        {
            // Grid
            glUnits.Table.SelectedRecords.Clear();
            // Details
            ResetDetails();
        }

        private void GlUnitsSelectedRecordsChanged(object sender, SelectedRecordsChangedEventArgs e)
        {
            var selecteds = glUnits.Table.SelectedRecords;

            if (selecteds == null || selecteds.Count <= 0) return;

            var unitId = (int)selecteds[0].Record.GetValue("Id");
            BuildUpDetails(unitId);
        }

        private bool CheckUnitName(string name)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var units = repository.Find<Unit>(u => u.IsValid && u.Name == name && u.UnitType.Type == "UnitType");
                return units.Any();
            }
        }       

        private void BtnSaveClick(object sender, EventArgs e)
        {
            if (String.IsNullOrWhiteSpace(txtUnit.Text))
            {
                LogTrace(Utilities.MajorUnitRequired, MessageType.Exclamation);
                return;
            }

            var isExist = CheckUnitName(txtUnit.Text);

            using (var repository = repositoryFactory.CreateRepository())
            {
                Record selected;
                var selecteds = glUnits.Table.SelectedRecords;
                try
                {
                    if (selecteds != null && selecteds.Count > 0)
                    {
                        // get the Unit Id
                        selected = selecteds[0].Record;
                        var unitId = (int) selected.GetValue("Id");
                        //
                        var item = repository.Find<Unit>(unitId);
                        // Validate the ItemBase model
                        if ((item.Name != txtUnit.Text) && isExist)
                        {
                            LogTrace(String.Format(Utilities.NameDuplicated, txtUnit.Text), MessageType.Exclamation);
                            return;
                        }
                        //
                        item.Name = txtUnit.Text;
                        item.Description = txtDesc.Text;
                        item.Address = txtAddress.Text;
                        item.Contact = txtContact.Text;
                        item.ContactTel = txtTel.Text;
                        item.IsValid = chkValid.Checked;
                        repository.TrySave<Unit>();

                        var index = glUnits.Table.Records.IndexOf(selected);
                        ResetGridByIndex(item.UnitType.Code, index);

                        LogTrace(String.Format(Utilities.SuccessUpdated, item.Name), MessageType.Information);
                    }
                    else
                    {
                        if (isExist)
                        {
                            LogTrace(String.Format(Utilities.NameDuplicated, txtUnit.Text), MessageType.Exclamation);
                            return;
                        }
                        // get the UnitType Id
                        var unitTypeId = (int) comUnitType.SelectedValue;
                        var unitType = repository.Find<ItemBase>(unitTypeId);
                        //
                        var item = new Unit
                                       {
                                           Name = txtUnit.Text,
                                           UnitType = unitType,
                                           Description = txtDesc.Text,
                                           Address = txtAddress.Text,
                                           Contact = txtContact.Text,
                                           ContactTel = txtTel.Text,
                                           IsValid = chkValid.Checked,
                                           CreateDate = DateTime.Now,
                                           ChildUnits = new List<Unit>()
                                       };

                        repository.Add(item);
                        repository.TrySave<Unit>();

                        ResetGrid(unitTypeId, item.Id);
                        LogTrace(String.Format(Utilities.SuccessMajorUnitAdded, item.Name), MessageType.Information);
                    }
                }
                catch (ValidationException ex)
                {
                    var message = String.Empty;
                    foreach (var entity in ex.Errors)
                    {
                        message = entity.Errors.Aggregate(message,
                                                          (current, error) =>
                                                          current +
                                                          String.Format("Property:'{0}' Error:{1}\r\n", error.Property,
                                                                        error.Message));
                    }
                    LogTrace(message, MessageType.Error);
                }
            }
        }
    }
}
